package com.hivekion.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hivekion.common.core.SystemConstant;
import com.hivekion.common.entity.TreeNode;
import com.hivekion.common.exception.BusinessException;
import com.hivekion.common.redis.RedisUtil;
import com.hivekion.system.domain.SysArea;
import com.hivekion.system.domain.vo.SysAreaCreateInputVo;
import com.hivekion.system.domain.vo.SysAreaUpdateInputVo;
import com.hivekion.system.domain.vo.SysAreaViewVo;
import com.hivekion.system.domain.vo.SysUserModelVo;
import com.hivekion.system.mapper.SysAreaMapper;
import com.hivekion.system.mapper.SysUserMapper;
import com.hivekion.system.service.ISysAreaService;
import com.hivekion.system.service.ISysUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class SysAreaServiceImpl extends ServiceImpl<SysAreaMapper, SysArea> implements ISysAreaService {

    @Autowired
    SysUserMapper userMapper;
    @Autowired
    ISysUserService userService;
    @Autowired
    private SysAreaMapper areaMapper;
    @Autowired
    private RedisUtil redisUtil;

    @Override
    public Boolean checkAreaNameUnique(String areaName, String areaId) {
        LambdaQueryWrapper<SysArea> areaLambdaQueryWrapper = Wrappers.lambdaQuery();
        areaLambdaQueryWrapper.eq(SysArea::getName, areaName);
        if (StringUtils.isNotEmpty(areaId)) {
            areaLambdaQueryWrapper.ne(SysArea::getId, areaId);
        }
        List<SysArea> list = areaMapper.selectList(areaLambdaQueryWrapper);
        return list.size() > 0;
    }

    @Override
    public List<SysArea> getAreaListByUserId(String userId) {
        SysUserModelVo info = userService.getInfo(userId);
        List<String> areaIds = info.getAreaIds();
        List<SysArea> allArea = this.getAllList();
        List<SysArea> list = allArea.stream().filter(x -> areaIds.contains(x.getId())).collect(Collectors.toList());

        List<SysArea> data = new ArrayList<>();
        for (SysArea area : list) {
            data.add(area);
            List<SysArea> children = getChildren(allArea, area.getId());
            data.addAll(children);
        }
        return data.stream().distinct().collect(Collectors.toList());
    }

    private List<SysArea> getChildren(List<SysArea> allArea, String parentId) {
        List<SysArea> data = new ArrayList<>();
        List<SysArea> areas = allArea.stream()
                .filter(x -> parentId.equals(x.getParentId()))
                .collect(Collectors.toList());
        for (SysArea area : areas) {
            data.add(area);
            List<SysArea> children = getChildren(allArea, area.getId());
            data.addAll(children);
        }
        return data;
    }


    @Override
    public boolean create(SysAreaCreateInputVo inputVo) {
        SysArea area = new SysArea();
        BeanUtils.copyProperties(inputVo, area);
        if (inputVo.getParentId() == null) {
            area.setParentId("");
        }
        boolean bl = areaMapper.insert(area) > 0;
        if (bl) this.updateRedis();
        return bl;
    }

    @Override
    public boolean delete(String areaId) {
        List<SysArea> children = getChildren(areaId);
        if (children.size() > 0) {
            throw new BusinessException(500, "该地区下还有地区");
        }
        boolean bl = areaMapper.deleteById(areaId) > 0;
        if (bl) this.updateRedis();
        return bl;
    }

    @Override
    public List<SysAreaViewVo> getList() {
        return buildViewVo(getParentAreas());
    }
    @Override
    public List<SysAreaViewVo> getList(String parentId){
        return buildViewVo(getParentAreas());
    }
    @Override
    public SysArea getInfo(String areaId) {
        List<SysArea> allList = getAllList();
        Optional<SysArea> first = allList.stream().filter(x -> areaId.equals(x.getId())).findFirst();
        if (first.isPresent()) {
            return first.get();
        } else {
            throw new BusinessException(500, "未找到地区信息");
        }
    }

    @Override
    public SysArea getByCode(String code) {
        LambdaQueryWrapper<SysArea> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(SysArea::getCode, code);
        List<SysArea> sysAreas = areaMapper.selectList(wrapper);
        if (sysAreas != null && sysAreas.size() > 0) {
            return sysAreas.get(0);
        }
        return null;
    }

    @Override
    public boolean update(SysAreaUpdateInputVo inputVo) {
        SysArea area = getArea(inputVo.getId());
        BeanUtils.copyProperties(inputVo, area);
        boolean bl = areaMapper.updateById(area) > 0;
        if (bl) this.updateRedis();
        return bl;
    }

    private List<SysAreaViewVo> buildViewVo(List<SysArea> list) {
        List<SysAreaViewVo> nodes = new ArrayList<>();
        if (list != null && list.size() > 0) {
            list.forEach(
                    area -> {
                        SysAreaViewVo vo = new SysAreaViewVo();
                        BeanUtils.copyProperties(area, vo);

                        vo.setChildren(null);
                        List<SysAreaViewVo> vos = getChilderenVo(area.getId());
                        if (vos != null && vos.size() > 0) {
                            vo.setChildren(vos);
                        }
                        nodes.add(vo);
                    });
        }
        return nodes;
    }

    private List<SysAreaViewVo> getChilderenVo(String parentId) {
        List<SysArea> list = getChildren(parentId);
        return buildViewVo(list);
    }

    /*
     * redis 缓存数据
     * */
    public List<SysArea> getAllList() {
        if (redisUtil.hasKey(SystemConstant.redis_area_data)) {
            List<SysArea> list =
                    JSON.parseArray(
                            redisUtil.get(SystemConstant.redis_area_data).toString(),
                            SysArea.class);
            return list;
        } else {
            QueryWrapper<SysArea> queryWrapper = new QueryWrapper<>();
            queryWrapper.orderByAsc("parent_id").orderByAsc("parent_id");
            List<SysArea> allArea = areaMapper.selectList(queryWrapper);
            redisUtil.set(SystemConstant.redis_area_data, JSON.toJSONString(allArea));
            return allArea;
        }
    }

    private void updateRedis() {
        List<SysArea> allArea = areaMapper.selectList(null);
        redisUtil.set(SystemConstant.redis_area_data, JSON.toJSONString(allArea));
    }

    @Override
    public List<TreeNode> getTreeSelect() {
        List<TreeNode> treeNodes = buildTreeNode(getParentAreas());
        return treeNodes;
    }

    private List<SysArea> getParentAreas() {
        List<SysArea> parentAreas =
                this.getAllList().stream()
                        .filter(x -> StringUtils.isBlank(x.getParentId()))
                        .sorted(Comparator.comparing(SysArea::getSortCode))
                        .collect(Collectors.toList());

        return parentAreas;
    }

    private List<SysArea> getParentAreas(String parentId) {
        List<SysArea> parentAreas =
                this.getAllList().stream()
                        .filter(x -> StringUtils.isBlank(x.getParentId()))
                        .sorted(Comparator.comparing(SysArea::getSortCode))
                        .collect(Collectors.toList());

        return parentAreas;
    }

    private List<TreeNode> buildTreeNode(List<SysArea> list) {
        List<TreeNode> treeNodes = new ArrayList<>();
        if (list != null && list.size() > 0) {
            list.forEach(
                    area -> {
                        TreeNode node = new TreeNode(area.getId(), area.getName(), area.getId());
                        node.setData(area);
                        List<TreeNode> children = this.getChildrenNode(area.getId());
                        if (children != null && children.size() > 0) {
                            node.setLeaf(false);
                            node.setTreeType(1);
                            node.setChildren(children);
                        } else {
                            node.setLeaf(true);
                        }
                        treeNodes.add(node);
                    });
        }
        return treeNodes;
    }

    @Override
    public List<TreeNode> getChildrenNodeList(String parentId) {
        return buildTreeNodeList(getChildren(parentId));
    }

    @Override
    public String getPath(String pathId) {
        List<SysArea> allList = getAllList();
        Optional<SysArea> area = allList.stream().filter(x -> pathId.equals(x.getId())).findFirst();
        String path = pathId;
        if (area.isPresent()) {
            String parentArea = area.get().getParentId();
            if (StringUtils.isNotBlank(parentArea)) {
                String str = getParentPath(allList, parentArea, path);
                if (StringUtils.isNotBlank(str)) {
                    path = str + "," + path;
                }
            }
        }
        return path;
    }

    @Override
    public boolean hashChildren(String pathId) {
        List<SysArea> allList = getAllList();
        Optional<SysArea> first = allList.stream().filter(x -> x.getParentId().equals(pathId)).findFirst();
        return first.isPresent();
    }

    @Override
    public List<SysArea> getChildAreas(String id) {
        List<SysArea> allList = getAllList();
        return allList.stream().filter(x -> x.getParentId().equals(id)).collect(Collectors.toList());
    }

    private String getParentPath(List<SysArea> allList, String pathId, String path) {
        Optional<SysArea> first = allList.stream().filter(x -> pathId.equals(x.getId())).findFirst();
        if (first.isPresent()) {
            String parentArea = first.get().getParentId();
            if (StringUtils.isNotBlank(parentArea)) {
                String str = getParentPath(allList, parentArea, path);
                if (StringUtils.isNotBlank(str)) {
                    return str + "," + pathId;
                }
            } else {
                return pathId;
            }
        }
        return "";
    }

    private List<TreeNode> getChildrenNode(String parentId) {
        List<SysArea> list = getChildren(parentId);
        return buildTreeNode(list);
    }

    private List<SysArea> getChildren(String parentId) {
        List<SysArea> allList = this.getAllList();
        List<SysArea> list =
                allList.stream()
                        .filter(t -> parentId.equals(t.getParentId()))
                        .sorted(Comparator.comparing(SysArea::getSortCode))
                        .collect(Collectors.toList());
        return list;
    }

    private SysArea getArea(String areaId) {
        SysArea area = areaMapper.selectById(areaId);
        if (area == null) {
            throw new BusinessException(500, "未找到部门信息");
        }
        return area;
    }

    private List<TreeNode> buildTreeNodeList(List<SysArea> list) {
        List<TreeNode> treeNodes = new ArrayList<>();
        if (list != null && list.size() > 0) {
            list.forEach(
                    area -> {
                        TreeNode node = new TreeNode(area.getId(), area.getName(), area.getId());
                        List<TreeNode> children = this.getChildrenNode(area.getId());
                        if (children != null && children.size() > 0) {
                            node.setChildren(children);
//				      treeNodes.addAll(children);
                        }
                        treeNodes.add(node);
                    });
        }
        return treeNodes;
    }
}
